
package com.innovamed.websocket.utils.websocket;

import java.lang.reflect.Field;
import java.net.InetSocketAddress;

import javax.websocket.RemoteEndpoint.Async;
import javax.websocket.Session;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import com.innovamed.websocket.constants.RedisConstants;
import com.innovamed.websocket.model.SessionInfo;
import com.innovamed.websocket.utils.queue.RoutingKeyGenerator;
import com.innovamed.websocket.utils.redis.RedisUtils;

import cn.hutool.json.JSONUtil;


/**
 * Copyright: Copyright (c) Jun_Zhou @PackageName:com.innovamed.websocket.utils @Description:
 * WebSocket相关的工具类;
 *
 * @version: v1.0.0
 * @author: JunZhou @Email: 1769676159@qq.com @Site: CERNO
 * @date: 2019/8/25 9:38
 */
@Component
public class WebSocketUtils
{
	public static RedisTemplate<String, Object> redisTemplate;
	
	@Autowired
	public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate)
	{
		WebSocketUtils.redisTemplate = redisTemplate;
	}
	
	public static RedisUtils redisUtils;
	
	@Autowired
	public void setRedisUtils(RedisUtils redisUtils)
	{
		WebSocketUtils.redisUtils = redisUtils;
	}
	
	/**
	 * 存储客户端的session信息到Redis中;
	* @param session:当前会话;
	* @param userId:当前用户的Id;
	*/
	public void saveSessionInfoToRedis(Session session, String sessionId)
	{
		
		//InetSocketAddress remoteAddress = WebSocketUtils.getRemoteAddress(session);
		//System.out.println(remoteAddress);
		//切换Redis数据库;
		redisUtils.switchRedisDB(redisTemplate, RedisConstants.USERINFO_DB_INDEX);
		String defaultRouteKey = RoutingKeyGenerator.generateDefaultRouteKey();
		//redisTemplate.opsForValue().set(RedisConstants.SESSION_CACHE_NAME_SPACE+userId, defaultRouteKey);
		SessionInfo sessionInfo = new SessionInfo();
	    sessionInfo.setRouteKey(defaultRouteKey);
	    sessionInfo.setSessionId(sessionId);
	    String sessionInfoStr = JSONUtil.toJsonPrettyStr(sessionInfo);
		redisTemplate.opsForValue().set(sessionId, sessionInfoStr);
	}
	
	/**
	  *   从Redis中移除指定的session信息;
	 * @param session
	 * @param userId
	 */
	public void removeSessionInfoToRedis(String sesionKey)
	{
		redisUtils.switchRedisDB(redisTemplate, RedisConstants.USERINFO_DB_INDEX);
		redisTemplate.delete(sesionKey);
	}
	
	/**
	  * 获取建立链接的WS的远程端口的IP地址;
	 * @param session
	 * @return
	 */
	public static InetSocketAddress getRemoteAddress(Session session)
	{
		if (session == null) { return null; }
		Async async = session.getAsyncRemote();
		// 在Tomcat 8.0.x版本有效
		// InetSocketAddress addr = (InetSocketAddress)
		// getFieldInstance(async,"base#sos#socketWrapper#socket#sc#remoteAddress");
		// 在Tomcat 8.5以上版本有效
		InetSocketAddress addr = (InetSocketAddress) getFieldInstance(async, "base#socketWrapper#socket#sc#remoteAddress");
		return addr;
	}
	
	/**
	 * 获取字段实例;
	 * @param obj
	 * @param fieldPath
	 * @return
	 */
	private static Object getFieldInstance(Object obj, String fieldPath)
	{
		String fields[] = fieldPath.split("#");
		for (String field : fields)
		{
			obj = getField(obj, obj.getClass(), field);
			if (obj == null) { return null; }
		}
		return obj;
	}
	
	/**
	 * 通过反射获取字段值;
	 *
	 * @param obj
	 * @param clazz
	 * @param fieldName
	 * @return
	 */
	private static Object getField(Object obj, Class<?> clazz, String fieldName)
	{
		for (; clazz != Object.class; clazz = clazz.getSuperclass())
		{
			try
			{
				Field field;
				field = clazz.getDeclaredField(fieldName);
				field.setAccessible(true);
				return field.get(obj);
			}
			catch (Exception e)
			{}
		}
		return null;
	}
}
